#include <stdio.h>
#include <stdlib.h>
#include <math.h>

typedef enum { false, true } bool;
typedef struct DistNode *Dist;
struct DistNode {
    int *dist; /* 距离值数组 */
    bool *deleted; /* 删除标识的数组 */
    int capacity; /* 距离总数量 */
    int size; /* 当前剩余元素数量 */
};

int FindMax(Dist D) {
    int i;

    i = 1;
    while (D->deleted[i] == true) {
        i++;
    } /* 第一个没被删除的距离是当前最大的 */
    return D->dist[i];
}

bool Check(int x_value, int *x, int n, Dist D) {
    /* 检查|x_value-x[i]| in D是否对所有已经赋值的x[i]都成立 */
    int i, j, v;
    bool ret;

    ret = true;
    for (i = 0; i < n; i++) {
        if (x[i] != -1) { /* 若x[i]已经赋值 */
            v = abs(x_value - x[i]);
            for (j = 0; j < D->capacity; j++) { /* 在D中找v */
                if (D->deleted[j] == false && D->dist[j] == v) {
                    break;
                }
            }
            if (j == D->capacity) { /* 若v不在D中 */
                ret = false;
                break;
            }
        }
    }
    return ret;
}

void Delete(int v, Dist D) {
    /* 从D中删除v */
    int i;

    for (i = D->capacity - 1; i >= 0; i--) {
        if (D->deleted[i] == false && D->dist[i] == v) {
            D->deleted[i] = true;
            D->size--;
            break;
        }
    }
}

void Insert(int v, Dist D) {
    /* 将v从D中恢复 */
    int i;

    for (i = D->capacity - 1; i >= 0; i--) {
        if (D->deleted[i] == true && D->dist[i] == v) {
            D->deleted[i] = false;
            D->size++;
            break;
        }
    }
}

int CmpDist(const void *a, const void *b) {
    return ((*(const int*)a) < (*(const int*)b)) ? 1 : -1;
}

/* 算法15-6：点集重构问题回溯算法的伪代码 PointSetReconstruction(x, D, n, left, right) */
bool PointSetReconstruction(int *x, Dist D, int n, int left, int right) {
    bool result;
    int d_max, i;

    result = false; /* 初始化标志 */
    if (D->size == 0) { /* 若D为空集 */
        result = true; /* 则顺利结束 */
    } else {
        d_max = FindMax(D); /* 取D中最大值 */
        /* 以下枚举两种可能：x[left] = x[n-1]-d_max 或 x[right] = d_max */
        /* 可能性1：x[left] = x[n-1]-d_max */
        if (Check(x[n - 1] - d_max, x, n, D) == true) {
            x[left] = x[n - 1] - d_max; /* 将x[left]加入；然后更新D */
            for (i = 0; i < left; i++) {
                Delete(abs(x[left] - x[i]), D);
            }
            for (i = right + 1; i < n; i++) {
                Delete(abs(x[left] - x[i]), D);
            }
            result = PointSetReconstruction(x, D, n, left + 1,
                                            right); /* 继续深度优先搜索 */
            if (result == false) { /* 若此路不通，则回溯 */
                /* 消除 x[left] 的影响，恢复原有的D */
                for (i = 0; i < left; i++) {
                    Insert(abs(x[left] - x[i]), D);
                }
                for (i = right + 1; i < n; i++) {
                    Insert(abs(x[left] - x[i]), D);
                }
            }
        } /* 完成可能性1的检查 */
        if (result == false) { /* 若可能性1不可行 */
            /* 考虑可能性2：x[right] = d_max */
            if (Check(d_max, x, n, D) == true) {
                x[right] = d_max; /* 将x[right]加入；然后更新D */
                for (i = 0; i < left; i++) {
                    Delete(abs(x[right] - x[i]), D);
                }
                for (i = right + 1; i < n; i++) {
                    Delete(abs(x[right] - x[i]), D);
                }
                result = PointSetReconstruction(x, D, n, left,
                                                right - 1); /* 继续深度优先搜索 */
                if (result == false) { /* 若此路不通，则回溯 */
                    /* 消除 x[right] 的影响，恢复原有的D */
                    for (i = 0; i < left; i++) {
                        Insert(abs(x[right] - x[i]), D);
                    }
                    for (i = right + 1; i < n; i++) {
                        Insert(abs(x[right] - x[i]), D);
                    }
                }
            } /* 完成可能性2的检查 */
        }
    } /* 当前子问题搜索完成 */
    return result;
}
/* 算法15-6 结束 */

int main(void) {
    int m, n, i;
    Dist D; /* 距离集合 */
    int *x; /* 坐标集合 */

    /* 读入m个距离值，创建距离集合 */
    scanf("%d", &m);
    D = (Dist)malloc(sizeof(struct DistNode));
    D->capacity = m;
    D->size = m;
    D->dist = (int *)malloc(sizeof(int) * m);
    D->deleted = (bool *)malloc(sizeof(bool) * m);
    for (i = 0; i < m; i++) {
        scanf("%d", &D->dist[i]);
        D->deleted[i] = false;
    }
    qsort(D->dist, m, sizeof(int), CmpDist); /* 将距离值从大到小排序 */
    n = ((int)sqrt((m << 3) +1) +1) >>
        1; /* 由距离数量反推坐标点的数量 */
    x = (int *)malloc(sizeof(int) * n);
    for (i = 0; i < n; i++) {
        x[i] = -1; /* 初始化坐标值为任何不可能是正确坐标的值 */
    }
    x[0] = 0;
    x[n - 1] = D->dist[0]; /* 最后一个点的坐标确定为最大距离值 */
    D->deleted[0] = true; /* 删除最大距离 */
    D->size--;
    if (PointSetReconstruction(x, D, n, 1,
    n - 2) == true) { /* 求解并输出结果 */
        printf("%d", x[0]);
        for (i = 1; i < n; i++) {
            printf(" %d", x[i]);
        }
        printf("\n");
    }

    return 0;
}